/*
    File Name: ValidatorMojo.java
    Creator: Bob Hogg <hogg.bob.2@gmail.com>
    Creation Date: December 21, 2014
    Purpose: Main file for the HTML 5 Validator Maven plugin.

    Copyright (C) 2015, Bob Hogg. All rights reserved.
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

package com.googlecode.ValidatorMavenPlugin;

import java.io.*;
import java.nio.file.*;
import java.util.*;

import com.google.common.collect.*;
import org.apache.maven.plugin.*;
import org.apache.maven.plugin.logging.*;

/**
    Goal which validates an HTML file (or a folder thereof) with Validator.nu
    @goal validate
    @phase process-sources
**/
public class ValidatorMojo extends AbstractMojo
{
    /**
        filesToValidate is a list of files to validate. (Folders are allowed)
        @parameter
        @required
    **/
    private List<File> filesToValidate;

    /**
        vnuCommand is the VNU executable on your file system.
        @parameter
        @required
    **/
    private String vnuCommand;

    private Log log = getLog();

    private ProcessBuilder pb = new ProcessBuilder();

    /**
        extensionList is a list of extensions to validate
        @parameter
    **/
    private List<String> extensionList;

    // walk the folder tree
    private void handleFolder(File folderToValidate) throws MojoExecutionException
    {
        for(File file : folderToValidate.listFiles())
        {
            if(!file.exists() || !file.canRead())
            {
                throw new MojoExecutionException("Error: Cannot find file " + file);
            }
            else if(file.isDirectory())
            {
                handleFolder(file);
            }
            else
            {
                handleFile(file);
            }
        }
    }

    /**
        execute runs through all files specified in the POM, recursively validating them as needed.
        @throws MojoExecutionException If any file is invalid or an error occurs.
    **/
    public void execute() throws MojoExecutionException
    {
        if(extensionList == null)
        {
            extensionList = ImmutableList.of("html", "htm", "xml");
        }
        ListIterator<File> fileListIterator = filesToValidate.listIterator();
        while(fileListIterator.hasNext())
        {
            File fileToValidate = fileListIterator.next();
            log.info("File: " + fileToValidate);
            if(!fileToValidate.exists() || !fileToValidate.canRead())
            {
                throw new MojoExecutionException("Error: Cannot find file " + fileToValidate);
            }

            if(fileToValidate.isDirectory())
            {
                handleFolder(fileToValidate);
            }
            else
            {
                handleFile(fileToValidate);
            }
        }
    }

    // validates a file
    private void handleFile(File fileToValidate) throws MojoExecutionException
    {
        String errors = validateFile(fileToValidate);
        if(! errors.isEmpty())
        {
            log.error("Validation of file " + fileToValidate + " failed!\n" + errors);
            throw new MojoExecutionException("Validation of file " + fileToValidate + " failed!");
        }
    }

    /**
        validateFile validates the given file and returns any errors
        @param fileToValidate File that must be validated, or a folder containing such files
        @return An error string if there was any
    **/
    private String validateFile(File fileToValidate)
    {
        boolean needsValidation = false;
        for(String extension: extensionList)
        {
            if(fileToValidate.getName().endsWith(extension))
            {
                needsValidation = true;
                break;
            }
        }
        if(! needsValidation)
        {
            return "";
        }
        log.info("Validating file " + fileToValidate);
        try
        {
            // FIXME don't need to use processes any more!
            pb.command(vnuCommand, "--format", "text", fileToValidate.getPath());
            Path tmpPath = Files.createTempFile("vnu", "txt");
            pb.redirectError(tmpPath.toFile());
            Process process = pb.start();
            process.waitFor();
            if(process.exitValue() == 0)
            {
                return "";
            }
            else
            {
                StringBuffer errorBuffer = new StringBuffer();
                Scanner scanner = new Scanner(tmpPath);
                while(scanner.hasNextLine())
                {
                    errorBuffer.append(scanner.nextLine() + "\n");
                }
                return errorBuffer.toString();
            }
        }
        catch(RuntimeException re)
        {
            throw re;
        }
        catch(Exception e)
        {
            return e.getLocalizedMessage();
        }
    }
}
